package gis.web.demo;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import gis.algorithm.Extent;
import gis.algorithm.GeoPoint;
import gis.algorithm.GeoUtils;
import gis.algorithm.Legend;
import gis.algorithm.RenderMethod;
import gis.algorithm.voronoi.RqVoronoi;
import gis.algorithm.voronoi.Vertex;
import gis.algorithm.voronoi.VoronoiArg;
import gis.algorithm.voronoi.VoronoiCalculator;
import gis.algtest.BizBts;
import gis.algtest.BizService;
import gis.algtest.Region;
import gis.core.exception.LogicalException;

/**
 * 泰森多边形
 */
@Controller("Service_Voronoi4326")
@RequestMapping({"/service/voronoi4326"})
public class Voronoi4326 {
    private static Logger logger = LoggerFactory.getLogger(Voronoi4326.class);
    private static VoronoiCalculator calculator = null;

    /**
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(method = RequestMethod.GET)
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        RqVoronoi rq;

        try {
            int x = Integer.parseInt(request.getParameter("x"));
            int y = Integer.parseInt(request.getParameter("y"));
            int z = Integer.parseInt(request.getParameter("z"));
            int wkid = Integer.parseInt(request.getParameter("wkid"));
            double resolution = Double.parseDouble(request.getParameter("r"));
            double originX = Double.parseDouble(request.getParameter("ox"));
            double originY = Double.parseDouble(request.getParameter("oy"));

            rq = new RqVoronoi();
            rq.setX(x);
            rq.setY(y);
            rq.setZ(z);
            rq.setWkid(wkid);
            rq.setResolution(resolution);
            rq.setOriginX(originX);
            rq.setOriginY(originY);
        } catch (Exception e) {
            logger.debug(e.getMessage(), e);
            output(response, null);
            return;
        }

        // 构造请求图片的边界数据
        GeoPoint sPoint = GeoUtils.getLeftTopPoint(rq.getOriginX(), rq.getOriginY(), rq.getResolution(), rq.getX(), rq.getY());
        GeoPoint ePoint = GeoUtils.getRightBottomPoint(rq.getOriginX(), rq.getOriginY(), rq.getResolution(), rq.getX(), rq.getY());
        Extent extent = new Extent(sPoint.getX(), ePoint.getX(), ePoint.getY(), sPoint.getY());

        // 请求的图层类型
        int layer = 0;
        try {
            layer = Integer.parseInt(request.getParameter("layer"));
        } catch (Exception e) {
            layer = 0;
        }

        BufferedImage image = null;
        try {
            VoronoiCalculator calc = getCalculator();
            switch (layer) {
                case 1: // 三角网线条图
                    image = calc.createDelaunayLineByT(rq, extent, Color.PINK);
                    break;
                case 2: // 三角网线条图
                    image = calc.createDelaunayLineByE(rq, extent, Color.PINK);
                    break;
                default: // 泰森多边形色块图
                    image = calc.createVoronoiColorImage(rq, extent);
            }
        } catch (LogicalException e) {
            logger.error(e.getMessage(), e);
        }
        output(response, image);
        return;
    }

    /**
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        try {
            double x = Double.parseDouble(request.getParameter("x"));
            double y = Double.parseDouble(request.getParameter("y"));

            GeoPoint p = new GeoPoint();
            p.setX(x);
            p.setY(y);

            VoronoiCalculator calc = getCalculator();
            long id = calc.getLocate(p.getX(), p.getY());
            BizBts obj = findBizObj(id);

            String body = "{}";
            if (obj != null) {
                String locate = findRegion(p.getX(), p.getY());
                body = "{locate:\"" + locate + "\",id:\"" + obj.getBtsId()
                        + "\",district:\"" + obj.getDistrictName()
                        + "\",name:\"" + obj.getBtsName() + "\",x:\""
                        + obj.getLongitude() + "\",y:\"" + obj.getLatitude()
                        + "\"}";
            }
            output(response, 200, body);
        } catch (Exception e) {
            logger.debug(e.getMessage(), e);
            output(response, 500, e.getMessage());
        }
    }

    /**
     * @throws LogicalException
     */
    private static synchronized VoronoiCalculator getCalculator()
            throws LogicalException {
        if (calculator == null) {
            calculator = new VoronoiCalculator(getArg());
        }
        return calculator;
    }

    /**
     * 获取泰森多边形算法基础数据
     *
     * @return
     */
    private static VoronoiArg getArg() {
        BizBts[] btses = BizService.getInstance().getBtses();

        List<Vertex> vertexs = new ArrayList<Vertex>();
        for (int i = 0; i < btses.length; i++) {
            BizBts bts = btses[i];
            double lon = bts.getLongitude();
            double lat = bts.getLatitude();

            Vertex vertex = new Vertex();
            vertex.setId(bts.getBtsId());
            vertex.setX(lon);
            vertex.setY(lat);
            vertex.setValue(bts.getTchTraf());
            vertexs.add(vertex);
        }

        VoronoiArg arg = new VoronoiArg();
        arg.setVertexs(vertexs);
        arg.setOptimize(true);
        arg.setRenderMethod(RenderMethod.Avg);
        arg.setLegends(getLegends());
        return arg;
    }

    /**
     * 获取当前图例设置
     *
     * @return
     */
    private static List<Legend> getLegends() {
        List<Legend> legends = new ArrayList<Legend>();

        Legend legend1 = new Legend();
        legend1.setColor(Color.GREEN);
        legend1.setValue(0);
        legend1.setText(String.valueOf(legend1.getValue()));
        legends.add(legend1);

        Legend legend2 = new Legend();
        legend2.setColor(Color.RED);
        legend2.setValue(300);
        legend2.setText(String.valueOf(legend2.getValue()));
        legends.add(legend2);

        return legends;
    }

    /**
     * @param response
     * @param image
     */
    private void output(HttpServletResponse response, BufferedImage image) {
        response.setContentType("image/png");
        response.setHeader("pragma", "no-cache");
        response.setHeader("cache-control", "no-cache");
        response.setDateHeader("expires", -1);

        if (image != null) {
            ServletOutputStream output;
            try {
                output = response.getOutputStream();
                ImageIO.write(image, "png", output);
                output.close();
            } catch (IOException e) {
            }
        }
    }

    /**
     * @param response
     * @param status
     * @param body
     */
    private void output(HttpServletResponse response, int status, String body) {
        response.setStatus(status);
        try {
            response.getWriter().write(body);
        } catch (IOException ex) {
        }
    }

    /**
     * 根据业务编号查找业务对象
     *
     * @param id
     * @return
     */
    private BizBts findBizObj(long id) {
        if (id == -1) {
            return null;
        }
        BizBts[] bizBtses = BizService.getInstance().getBtses();
        for (BizBts bizBts : bizBtses) {
            if (bizBts.getBtsId() == id) {
                return bizBts;
            }
        }
        return null;
    }

    /**
     * 查找归属的行政区域
     *
     * @param x
     * @param y
     * @return
     */
    private String findRegion(double x, double y) {
        Region[] regions = BizService.getInstance().getRegions();
        for (Region region : regions) {
            if (!region.getLevel().equals("Level3")) {
                continue;
            }
            GeoPoint[] points = region.getRingPoints().toArray(new GeoPoint[0]);
            if (GeoUtils.isPointInPolygon(points, x, y)) {
                return region.getName();
            }
        }
        return null;
    }
}
